#include "raft.h"
#include <boost/archive/text_iarchive.hpp>
#include <boost/archive/text_oarchive.hpp>
#include <memory>
#include "config.h"
#include "util.h"
#include <atomic>

namespace raftCore 
{
// Follower 接收 Leader 发送的日志同步（或心跳）请求时的处理逻辑，是 Raft 日志复制的核心
void Raft::AppendEntries1(const raftRpcProctoc::AppendEntriesArgs* args, raftRpcProctoc::AppendEntriesReply* reply) {
    std::lock_guard<std::mutex> locker(m_mtx);  // 加锁，保证线程安全
    reply->set_appstate(AppNormal);             // 标记网络正常
  
    // 步骤1：检查任期（Raft 安全性核心：任期小的请求无效）
    if (args->term() < m_currentTerm) {
        reply->set_success(false);
        reply->set_term(m_currentTerm);  // 回复自己的当前任期（让 Leader 更新）
        reply->set_updatenextindex(-100);  // 无效索引，提示 Leader 无需调整
        common::DPrintf("[func-AppendEntries-rf{%d}] 拒绝请求：Leader{%d}的term{%d} < 本地term{%d}\n",
                        m_me, args->leaderid(), args->term(), m_me, m_currentTerm);
        return;
    }
  
    common::DEFER [&]() { persist(); };  // 延迟执行持久化（方法结束时保存状态）
  
    // 步骤2：如果请求任期更大，更新自身为 Follower 并同步任期
    if (args->term() > m_currentTerm) {
        m_status = Follower;  // 转为 Follower
        m_currentTerm = args->term();  // 更新任期
        m_votedFor = -1;  // 重置投票（新任期未投票）
    }
  
    common::Assert(args->term() == m_currentTerm, "args.term 必须等于当前任期");  // 确保任期一致
    m_status = Follower;  // 即使任期相同，Candidate 收到 Leader 请求也需转为 Follower
    m_lastResetElectionTime = common::Now();  // 重置选举定时器（收到 Leader 消息，避免触发新选举）
  
    // 步骤3：检查日志匹配性（前序日志是否一致，Raft 日志复制的关键）
    // 情况1：请求的前序日志索引超过本地最大日志索引（本地日志不足）
    if (args->prevlogindex() > getLastLogIndex()) {
        reply->set_success(false);
        reply->set_term(m_currentTerm);
        reply->set_updatenextindex(getLastLogIndex() + 1);  // 提示 Leader 从本地最后一条日志的下一个索引开始发送
        return;
    }
    // 情况2：请求的前序日志索引在快照之前（本地已通过快照截断该日志）
    // 快照是状态机处理完所有日志条目后的结果，记录该快照对应的 “最后包含的日志索引” 和 “任期”。
    else if (args->prevlogindex() < m_lastSnapshotIncludeIndex) {
        // 状态机已经处理完了，那么就不需要同步了
        reply->set_success(false);
        reply->set_term(m_currentTerm);
        reply->set_updatenextindex(m_lastSnapshotIncludeIndex + 1);  // 提示 Leader 从快照后的索引开始发送
        return;
    }
  
    // 步骤4：前序日志存在，检查是否匹配（索引和任期均需一致）
    if (matchLog(args->prevlogindex(), args->prevlogterm())) {
        // 日志匹配，处理新日志条目
        for (int i = 0; i < args->entries_size(); i++) {
            auto log = args->entries(i);  // 遍历待同步的日志
            if (log.logindex() > getLastLogIndex()) {
                // 日志索引超过本地最大索引，直接追加
                m_logs.push_back(log);
            }
            else {
                // 日志索引已存在，检查任期是否一致
                if (m_logs[getSlicesIndexFromLogIndex(log.logindex())].logterm() != log.logterm()) {
                    // 任期不一致，替换本地日志（截断冲突部分，以 Leader 日志为准）
                    m_logs[getSlicesIndexFromLogIndex(log.logindex())] = log;
                }
                // 任期一致则无需处理（日志已同步）
            }
        }
  
        // 步骤5：更新提交索引（以 Leader 告知的提交索引为准，不超过本地最后一条日志）
        if (args->leadercommit() > m_commitIndex) {
            m_commitIndex = std::min(args->leadercommit(), getLastLogIndex());
        }
  
        reply->set_success(true);  // 日志同步成功
        reply->set_term(m_currentTerm);
        return;
    } 
    else {
        // 步骤6：前序日志不匹配，优化 Leader 的 nextIndex（减少重试次数）
        reply->set_updatenextindex(args->prevlogindex());
        // 向前查找第一个与前序日志任期不同的索引，提示 Leader 从该索引开始发送
        for (int index = args->prevlogindex(); index >= m_lastSnapshotIncludeIndex; --index) {
            if (getLogTermFromLogIndex(index) != getLogTermFromLogIndex(args->prevlogindex())) {
                reply->set_updatenextindex(index + 1);
                break;
            }
        }
        reply->set_success(false);
        reply->set_term(m_currentTerm);
        return;
    }
}

// 定期将已提交的日志应用到状态机，并通知应用层（如 KV 存储）。
void Raft::applierTicker() {
    while (true) {  // 无限循环，持续处理
        m_mtx.lock();
        // 调试信息：打印 Leader 的提交和应用进度
        if (m_status == Leader) {
            common::DPrintf("[Raft::applierTicker() - raft{%d}]  m_lastApplied{%d}   m_commitIndex{%d}",
                            m_me, m_lastApplied, m_commitIndex);
        }
        auto applyMsgs = getApplyLogs();  // 获取待应用的日志（m_lastApplied 到 m_commitIndex 之间的日志）
        m_mtx.unlock();
    
        // 将日志应用消息发送给应用层（如 KV 服务器）
        if (!applyMsgs.empty()) {
            common::DPrintf("[func- Raft::applierTicker()-raft{%d}] 向kvserver报告的applyMsgs长度为：{%d}", m_me, applyMsgs.size());
        }
        for (auto& message : applyMsgs) {
            applyChan->Push(message);  // 推送到消息队列
        }
    
        common::SleepMs(common::APPLY_INTERVAL);  // 间隔一段时间（如 10ms）再次检查
    }
}

// 用于处理 Leader 发送的快照安装请求（当 Follower 日志落后太多时，Leader 直接发送快照而非逐条同步日志）。
bool Raft::CondInstallSnapshot(int lastIncludedTerm, int lastIncludedIndex, std::string snapshot) {
    return true;  // 占位：实际需检查快照的任期和索引是否有效，更新本地快照信息并截断日志
    // 潜在实现逻辑：
    // 1. 若快照的 lastIncludedIndex <= commitIndex → 快照过时，返回 false
    // 2. 否则更新日志（截断旧日志）、commitIndex 和 lastApplied 至快照索引
    // 3. 持久化快照数据
}

// Candidate 发起选举的核心逻辑
void Raft::doElection() {
    std::lock_guard<std::mutex> g(m_mtx);  // 加锁保护共享状态
  
    if (m_status != Leader) {  // 仅非 Leader 节点发起选举
        common::DPrintf("[       ticker-func-rf(%d)              ]  选举定时器到期且不是leader，开始选举 \n", m_me);
        
        // 转为 Candidate，更新任期，给自己投票
        m_status = Candidate;
        m_currentTerm += 1;  // 任期自增（开启新任期）
        m_votedFor = m_me;   // 自己给自己投票
        persist();           // 持久化任期和投票记录
  
        // 统计同意票数（初始为1，自己已投）
        auto votedNum = std::make_shared<std::atomic<int>>(1);
        // 重置选举定时器（避免重复发起选举）
        m_lastResetElectionTime = common::Now();
  
        // 向所有其他节点发送 RequestVote RPC
        for (int i = 0; i < m_peers.size(); i++) {
            if (i == m_me) continue;  // 跳过自己
    
            // 获取自身最后一条日志的索引和任期（用于选举的日志完整性校验）
            int lastLogIndex = -1, lastLogTerm = -1;
            getLastLogIndexAndTerm(&lastLogIndex, &lastLogTerm);
    
            // 构造投票请求
            std::shared_ptr<raftRpcProctoc::RequestVoteArgs> requestVoteArgs =
                std::make_shared<raftRpcProctoc::RequestVoteArgs>();
            requestVoteArgs->set_term(m_currentTerm);
            requestVoteArgs->set_candidateid(m_me);
            requestVoteArgs->set_lastlogindex(lastLogIndex);
            requestVoteArgs->set_lastlogterm(lastLogTerm);
            auto requestVoteReply = std::make_shared<raftRpcProctoc::RequestVoteReply>();
    
            // 启动新线程发送投票请求（异步处理，避免阻塞）
            std::thread t(&Raft::sendRequestVote, this, i, requestVoteArgs, requestVoteReply, votedNum);
            t.detach();
        }
    }
}

// Leader 定期发送心跳（空 AppendEntries）维持 leadership
void Raft::doHeartBeat() {
    std::lock_guard<std::mutex> g(m_mtx);  // 加锁保护共享状态
  
    if (m_status == Leader) {  // 仅 Leader 发送心跳
        common::DPrintf("[func-Raft::doHeartBeat()-Leader: {%d}] 开始发送心跳\n", m_me);
  
        // 遍历所有 Follower 节点
        for (int i = 0; i < m_peers.size(); i++) {
            if (i == m_me) continue;  // 跳过自己
  
            // 若 Follower 的 nextIndex 落后于快照 → 发送快照而非日志
            if (m_nextIndex[i] <= m_lastSnapshotIncludeIndex) {
                std::thread t(&Raft::leaderSendSnapShot, this, i);  // 异步发送快照
                t.detach();
                continue;
            }
  
            // 构造 AppendEntries 请求（含日志或空心跳）
            int preLogIndex = -1, PrevLogTerm = -1;
            getPrevLogInfo(i, &preLogIndex, &PrevLogTerm);  // 获取 prevLogIndex 和 term
            
            std::shared_ptr<raftRpcProctoc::AppendEntriesArgs> appendEntriesArgs =
            std::make_shared<raftRpcProctoc::AppendEntriesArgs>();
            appendEntriesArgs->set_term(m_currentTerm);
            appendEntriesArgs->set_leaderid(m_me);
            appendEntriesArgs->set_prevlogindex(preLogIndex);
            appendEntriesArgs->set_prevlogterm(PrevLogTerm);
            appendEntriesArgs->set_leadercommit(m_commitIndex);  // 同步 Leader 的 commitIndex
  
            // 添加需要同步的日志条目（从 prevLogIndex+1 开始）
            if (preLogIndex != m_lastSnapshotIncludeIndex) {
                for (int j = getSlicesIndexFromLogIndex(preLogIndex) + 1; j < m_logs.size(); ++j) {
                    raftRpcProctoc::LogEntry* sendEntryPtr = appendEntriesArgs->add_entries();
                    *sendEntryPtr = m_logs[j];
                }
            } 
            else {
                // 若从快照后第一条日志开始同步，则添加所有日志
                for (const auto& item : m_logs) {
                    raftRpcProctoc::LogEntry* sendEntryPtr = appendEntriesArgs->add_entries();
                    *sendEntryPtr = item;
                }
            }
  
            // 断言：确保发送的日志长度正确
            common::Assert(appendEntriesArgs->prevlogindex() + appendEntriesArgs->entries_size() == getLastLogIndex(),
                            common::Format("日志长度不匹配"));
  
            // 异步发送 AppendEntries 请求
            const std::shared_ptr<raftRpcProctoc::AppendEntriesReply> appendEntriesReply =
                std::make_shared<raftRpcProctoc::AppendEntriesReply>();
            appendEntriesReply->set_appstate(Disconnected);
            std::thread t(&Raft::sendAppendEntries, this, i, appendEntriesArgs, appendEntriesReply,
                        std::make_shared<int>(1));
            t.detach();
        }
  
        // 更新心跳发送时间
        m_lastResetHearBeatTime = common::Now();
    }
}

// 非 Leader 节点的选举超时定时器：超时未收到心跳则发起选举
void Raft::electionTimeOutTicker() {
    while (true) {
        // 若当前是 Leader，无需选举，短暂休眠后重试
        while (m_status == Leader) {
            usleep(common::HEART_BEAT_TIMEOUT);  // 心跳间隔通常小于选举超时，避免无效轮询
        }
  
        // 计算需要休眠的时间（随机选举超时 - 已流逝时间）
        std::chrono::system_clock::time_point wakeTime{};
        std::chrono::duration<signed long int, std::ratio<1, 1000000000>> suitableSleepTime{};
        {
            m_mtx.lock();
            wakeTime = common::Now();
            suitableSleepTime = common::GetRandomizedElectionTimeout() + m_lastResetElectionTime - wakeTime;
            m_mtx.unlock();
        }
  
        // 休眠至选举超时（若剩余时间>1ms）
        if (std::chrono::duration<double, std::milli>(suitableSleepTime).count() > 1) {
            usleep(std::chrono::duration_cast<std::chrono::microseconds>(suitableSleepTime).count());
        }
  
        // 检查休眠期间是否收到心跳（重置了选举定时器）
        if (std::chrono::duration<double, std::milli>(m_lastResetElectionTime - wakeTime).count() > 0) {
            continue;  // 未超时，继续等待
        }
  
        // 超时未收到心跳 → 发起选举
        doElection();
    }
}

// 收集从 lastApplied+1 到 commitIndex 的日志条目（需按顺序应用到状态机）
std::vector<ApplyMsg> Raft::getApplyLogs() {
    std::vector<ApplyMsg> applyMsgs;
    // 断言：commitIndex 不能超过最后一条日志索引（避免越界）
    common::Assert(m_commitIndex <= getLastLogIndex(), common::Format("[func-getApplyLogs-rf{%d}] commitIndex 越界", m_me));
  
    // 从 lastApplied 开始，逐个应用至 commitIndex
    while (m_lastApplied < m_commitIndex) {
        m_lastApplied++;  // 应用下一条日志
        // 断言：日志索引与应用索引一致（确保顺序正确）
        common::Assert(m_logs[getSlicesIndexFromLogIndex(m_lastApplied)].logindex() == m_lastApplied,
                        common::Format("日志索引不匹配"));
    
        // 构造应用消息（含命令和索引）
        ApplyMsg applyMsg;
        applyMsg.CommandValid = true;
        applyMsg.SnapshotValid = false;
        applyMsg.Command = m_logs[getSlicesIndexFromLogIndex(m_lastApplied)].command();
        applyMsg.CommandIndex = m_lastApplied;
        applyMsgs.emplace_back(applyMsg);
    }

    return applyMsgs;
}

// 计算新日志条目应分配的索引（最后一条日志索引 + 1）
int Raft::getNewCommandIndex() {
    auto lastLogIndex = getLastLogIndex();
    return lastLogIndex + 1;
}

// Leader 计算发送给 Follower 的 prevLogIndex 和 prevLogTerm
// 用于构造 AppendEntries 请求的前置日志校验信息
void Raft::getPrevLogInfo(int server, int* preIndex, int* preTerm) {
    // 若 nextIndex 为快照后第一条日志 → prevLog 为快照的最后索引和任期
    if (m_nextIndex[server] == m_lastSnapshotIncludeIndex + 1) {
        *preIndex = m_lastSnapshotIncludeIndex;
        *preTerm = m_lastSnapshotIncludeTerm;
        return;
    }
    // 否则基于 nextIndex 计算（略，完整逻辑需结合日志存储）
    auto nextIndex = m_nextIndex[server];
    *preIndex = nextIndex - 1;
    *preTerm = m_logs[getSlicesIndexFromLogIndex(*preIndex)].logterm();
}

// 定期触发 Leader 向所有 Follower 发送心跳（或日志同步请求），维持 Leader 的统治地位（防止 Follower 因超时未收到心跳而发起新选举）。
void Raft::leaderHearBeatTicker() {
    // 无限循环：心跳定时器需要持续运行，确保 Leader 不断发送心跳
    while (true) {
        // 【非 Leader 节点处理】：若当前节点不是 Leader，无需发送心跳，进入休眠节省资源
        // 避免非 Leader 节点频繁拿锁/检查状态，优化性能
        while (m_status != Leader) {
            // 休眠 HeartBeatTimeout 毫秒（1000微秒=1毫秒，故 1000*HeartBeatTimeout 微秒=HeartBeatTimeout 毫秒）
            usleep(1000 * common::HEART_BEAT_TIMEOUT);
            // 备选方案：使用 C++11 时间接口（注释中保留）
            // std::this_thread::sleep_for(std::chrono::milliseconds(HeartBeatTimeout));
        }

        // 静态原子计数器（调试用）：记录心跳触发次数（原子变量确保多线程安全计数）
        static std::atomic<int32_t> atomicCount = 0;
  
        // 定义变量：
        // suitableSleepTime：计算出的"需要休眠的时间"（确保心跳间隔稳定）
        // wakeTime：本次计算睡眠时间时的"当前时间"（作为基准时间）
        std::chrono::duration<signed long int, std::ratio<1, 1000000000>> suitableSleepTime{};
        std::chrono::system_clock::time_point wakeTime{};

        // 【线程安全块】：获取当前时间并计算睡眠时间（需加锁保护共享变量 m_lastResetHearBeatTime）
        {
            std::lock_guard<std::mutex> lock(m_mtx);  // 加锁，防止多线程同时修改时间变量
            wakeTime = common::Now();  // 记录当前时间（作为后续计算的基准）
            // 计算"距离下一次心跳的剩余时间"：
            // 心跳间隔应为 HeartBeatTimeout 毫秒，上次重置心跳的时间 + 间隔时间 = 理论下次心跳时间
            // 理论下次心跳时间 - 当前时间 = 需要休眠的时间
            suitableSleepTime = std::chrono::milliseconds(common::HEART_BEAT_TIMEOUT) + m_lastResetHearBeatTime - wakeTime;
        }
  
        // 若需要休眠的时间 > 1 毫秒（避免无意义的短睡眠）
        if (std::chrono::duration<double, std::milli>(suitableSleepTime).count() > 1) {
            // 打印调试信息（紫色文字）：设置的睡眠时间（预期值）
            std::cout << atomicCount << "\033[1;35m leaderHearBeatTicker();函数设置睡眠时间为: "
                      << std::chrono::duration_cast<std::chrono::milliseconds>(suitableSleepTime).count() << " 毫秒\033[0m"
                      << std::endl;
            // 记录实际开始休眠的时间
            auto start = std::chrono::steady_clock::now();
  
            // 执行休眠（将计算出的时间转换为微秒，适配 usleep）
            usleep(std::chrono::duration_cast<std::chrono::microseconds>(suitableSleepTime).count());
            // 备选方案：使用 C++11 睡眠接口（注释中保留）
            // std::this_thread::sleep_for(suitableSleepTime);
  
            // 记录实际结束休眠的时间
            auto end = std::chrono::steady_clock::now();
  
            // 计算并打印实际休眠时间（调试用，验证是否与预期一致）
            std::chrono::duration<double, std::milli> duration = end - start;
            std::cout << atomicCount << "\033[1;35m leaderHearBeatTicker();函数实际睡眠时间为: " << duration.count()
                      << " 毫秒\033[0m" << std::endl;
            // 计数器自增（记录本次心跳周期）
            ++atomicCount;
        }
  
        // 检查：休眠期间是否重置过心跳定时器（即是否已发送过心跳）
        // 若 m_lastResetHearBeatTime > wakeTime，说明休眠期间已更新过心跳时间（无需重复发送）
        if (std::chrono::duration<double, std::milli>(m_lastResetHearBeatTime - wakeTime).count() > 0) {
            // 继续循环，等待下一次周期
            continue;
        }

        // 若未重置过定时器，说明到了发送心跳的时间，调用 doHeartBeat 发送心跳
        // DPrintf("[func-Raft::doHeartBeat()-Leader: {%d}] Leader的心跳定时器触发了\n", m_me);  // 调试日志（注释中保留）
        doHeartBeat();
    }
}

// Leader 向指定 Follower 发送快照的核心函数
// 当 Follower 的日志落后太多（例如 Follower 的 nextIndex 小于 Leader 的快照索引），Leader 会直接发送快照而非逐条同步旧日志，以减少网络传输开销
// 这是 Raft 协议中优化日志同步效率的关键机制。
void Raft::leaderSendSnapShot(int server) {
    // 加锁保护共享状态（避免发送快照时状态被其他线程修改）
    m_mtx.lock();

    // 构造快照发送请求参数（InstallSnapshotRequest）
    raftRpcProctoc::InstallSnapshotRequest args;
    args.set_leaderid(m_me);  // 设置发送方（当前 Leader 的 ID）
    args.set_term(m_currentTerm);  // 当前 Leader 的任期（用于 Follower 验证合法性）
    // 快照包含的最后一条日志的索引和任期（Follower 需以此为基准截断旧日志）
    args.set_lastsnapshotincludeindex(m_lastSnapshotIncludeIndex);
    args.set_lastsnapshotincludeterm(m_lastSnapshotIncludeTerm);
    args.set_data(m_persister->ReadSnapshot());  // 快照数据（实际业务状态，如 KV 存储的快照）

    // 定义响应对象（用于接收 Follower 的处理结果）
    raftRpcProctoc::InstallSnapshotResponse reply;

    // 解锁：发送 RPC 可能耗时，提前释放锁避免阻塞其他操作
    m_mtx.unlock();

    // 向目标 Follower 发送快照 RPC 请求（调用 Follower 的 InstallSnapshot 接口）
    bool ok = m_peers[server]->InstallSnapshot(&args, &reply);

    // 再次加锁：处理响应时需操作共享状态，需重新加锁
    m_mtx.lock();
    // 延迟解锁：函数退出时自动释放锁（无论 return 在哪里，确保不会死锁）
    common::DEFER [&]() { m_mtx.unlock(); };

    // 若 RPC 调用失败（如网络问题），直接返回
    if (!ok) {
        return;
    }

    // 检查：发送快照期间是否已不再是 Leader，或任期已变更（中间释放过锁，状态可能变化）
    // 若状态不符，无需继续处理（避免无效操作）
    if (m_status != Leader || m_currentTerm != args.term()) {
        return;
    }

    // 任期检查（Raft 安全性核心）：若 Follower 响应的任期更大，说明有新 Leader 出现
    if (reply.term() > m_currentTerm) {
        // 自我降级为 Follower（"三变"：更新任期、重置投票、切换状态）
        m_currentTerm = reply.term();  // 同步到更大的任期
        m_votedFor = -1;  // 新任期未投票
        m_status = Follower;  // 切换为 Follower
        persist();  // 持久化新状态（崩溃后可恢复）
        m_lastResetElectionTime = common::Now();  // 重置选举定时器（避免立即发起选举）
        return;
    }

    // 快照同步成功：更新该 Follower 的日志匹配状态
    // 1. matchIndex：记录 Follower 已同步的最大日志索引（此处为快照的最后索引）
    m_matchIndex[server] = args.lastsnapshotincludeindex();
    // 2. nextIndex：后续日志从快照后第一条开始同步（快照索引 + 1）
    m_nextIndex[server] = m_matchIndex[server] + 1;
}

// Leader 节点更新提交索引
// 日志条目需被集群中多数节点复制后才能被提交（应用到状态机），且为了安全性，仅允许提交当前任期内的日志条目。
// 该函数通过统计各节点的日志复制进度，确定最大可提交的日志索引，是保证集群日志一致性的关键逻辑。
void Raft::leaderUpdateCommitIndex() {
    // 初始化提交索引为快照包含的最后一条日志索引（快照内的日志已默认提交）
    m_commitIndex = m_lastSnapshotIncludeIndex;

    // 从最后一条日志索引开始，反向遍历至快照后第一条日志（寻找最大可提交的索引）
    // 反向遍历的原因：优先找更大的索引，确保 commitIndex 是最大可能的已提交索引
    for (int index = getLastLogIndex(); index >= m_lastSnapshotIncludeIndex + 1; index--) {
        int sum = 0;  // 统计已复制该索引日志的节点数量（包括自身）

        // 遍历所有节点，计算复制了该索引日志的节点数
        for (int i = 0; i < m_peers.size(); i++) {
            if (i == m_me) {
                // 自身作为 Leader，必然已拥有该日志（无需检查，直接计数）
                sum += 1;
                continue;
            }
            // 若 Follower 的 matchIndex（已复制的最大日志索引）>= 当前 index，说明该 Follower 已复制该日志
            if (m_matchIndex[i] >= index) {
                sum += 1;
            }
        }

        // 【Raft 安全性核心条件】：
        // 1. 已复制该日志的节点数超过集群半数（sum >= 多数，确保分布式一致性）
        // 2. 该日志的任期必须是当前任期（避免提交旧任期日志导致的状态不一致）
        if (sum >= m_peers.size() / 2 + 1 && getLogTermFromLogIndex(index) == m_currentTerm) {
            m_commitIndex = index;  // 更新提交索引为当前最大可提交的索引
            break;  // 找到最大索引后直接退出，无需继续检查更小的索引
        }
    }

    // 调试日志（注释中保留）：打印 Leader 提交索引更新结果
    // DPrintf("[func-leaderUpdateCommitIndex()-rf{%v}] Leader %d(term%d) commitIndex %d",
    //         m_me, m_me, m_currentTerm, m_commitIndex)
}

//进来前要保证logIndex是存在的，即≥rf.lastSnapshotIncludeIndex	，而且小于等于rf.getLastLogIndex()
bool Raft::matchLog(int logIndex, int logTerm) {
    // 断言：确保 logIndex 是有效的（未被快照截断且未超过当前最后一条日志索引）
    // 若不满足此条件，说明 logIndex 对应的日志不存在，直接触发调试断言失败
    common::Assert(logIndex >= m_lastSnapshotIncludeIndex && logIndex <= getLastLogIndex(),
                    common::Format("不满足：logIndex{%d}>=rf.lastSnapshotIncludeIndex{%d}&&logIndex{%d}<=rf.getLastLogIndex{%d}",
                    logIndex, m_lastSnapshotIncludeIndex, logIndex, getLastLogIndex()));

    // 核心逻辑：检查 logTerm 是否与 logIndex 对应的日志任期一致
    // getLogTermFromLogIndex(logIndex) 用于获取 logIndex 对应的实际任期
    return logTerm == getLogTermFromLogIndex(logIndex);
    
    // 注释中的完整逻辑（更清晰地处理快照边界情况）：
    // 1. 若 logIndex 是快照包含的最后一条日志索引 → 用快照的任期（m_lastSnapshotIncludeTerm）匹配
    // 2. 否则 → 从日志列表中获取该索引对应的任期匹配
    // if (logIndex == m_lastSnapshotIncludeIndex) {
    //     return logTerm == m_lastSnapshotIncludeTerm;
    // } else {
    //     return logTerm == m_logs[getSlicesIndexFromLogIndex(logIndex)].logterm();
    // }
}

// Raft节点持久化关键状态的核心函数
// 作用：将节点的关键状态（如当前任期、投票记录、日志等）持久化到稳定存储（如磁盘），
// 确保节点在崩溃重启后能恢复这些状态，是Raft协议实现容错性的关键机制。
void Raft::persist() {
    // 1. 序列化需要持久化的状态数据
    // persistData()是一个辅助函数（未在此处实现），负责将Raft节点的关键状态（如：
    // - 当前任期（m_currentTerm）
    // - 已投票给的节点（m_votedFor）
    // - 日志条目（m_logs）
    // 等）序列化为可存储的数据格式（通常通过序列化库如boost::archive实现，代码中包含相关头文件）。
    auto data = persistData();

    // 2. 将序列化后的数据保存到稳定存储
    // m_persister是一个持久化工具实例（如封装了磁盘IO的对象），
    // SaveRaftState方法负责将序列化后的data写入稳定存储（避免节点崩溃后数据丢失）。
    m_persister->SaveRaftState(data);
}

// 判断 Candidate 的日志是否“足够新”（满足 Raft 选举中的日志完整性要求）
// 作用：在选举过程中，接收投票请求的节点（Follower/Candidate）通过该函数判断请求投票的 Candidate 的日志是否至少与自己的日志一样新，
// 是 Raft 协议确保“只有日志完整的节点能当选 Leader”的核心判断逻辑。
bool Raft::UpToDate(int index, int term) {
    // 1. 获取当前节点最后一条日志的索引和任期
    int lastIndex = -1;  // 当前节点最后一条日志的索引
    int lastTerm = -1;   // 当前节点最后一条日志的任期
    // 调用辅助函数获取当前节点最后一条日志的索引和任期（封装了日志存储的细节，如处理快照截断等情况）
    getLastLogIndexAndTerm(&lastIndex, &lastTerm);

    // 2. 判断 Candidate 的日志是否“足够新”，满足以下任一条件即为“足够新”：
    //    a. Candidate 最后一条日志的任期（term）> 当前节点最后一条日志的任期（lastTerm）→ 任期更新，日志更完整；
    //    b. 两者任期相同（term == lastTerm），且 Candidate 最后一条日志的索引（index）≥ 当前节点的最后日志索引（lastIndex）→ 同任期下日志更长。
    return term > lastTerm || (term == lastTerm && index >= lastIndex);
}

// 核心辅助函数：同时获取当前节点最后一条日志的索引和任期（处理日志为空时的快照边界情况）
// 作用：统一封装“最后一条日志”的判断逻辑，兼顾两种场景：
// 1. 日志列表非空：直接取最后一条日志的索引和任期；
// 2. 日志列表为空（日志被快照截断）：使用快照中记录的“最后包含的日志索引和任期”。
// 是 Raft 中处理日志与快照关系的基础函数。
void Raft::getLastLogIndexAndTerm(int* lastLogIndex, int* lastLogTerm) {
    // 情况1：日志列表为空（说明所有日志已被快照包含，本地仅保留快照信息）
    if (m_logs.empty()) {
        // 从快照信息中获取最后一条被包含的日志索引和任期
        *lastLogIndex = m_lastSnapshotIncludeIndex;  // 快照包含的最后日志索引
        *lastLogTerm = m_lastSnapshotIncludeTerm;    // 快照包含的最后日志任期
        return;
    } 
    else {
        // 情况2：日志列表非空，直接取最后一条日志的索引和任期
        *lastLogIndex = m_logs[m_logs.size() - 1].logindex();  // 日志列表最后一条的索引
        *lastLogTerm = m_logs[m_logs.size() - 1].logterm();    // 日志列表最后一条的任期
        return;
    }
}

// 获取当前节点最后一条日志的索引（封装了日志与快照的边界处理）
// 作用：在 Raft 协议中，最后一条日志的索引用于日志同步（如 AppendEntries 的 prevLogIndex）、
// 选举中的日志完整性校验（比较 Candidate 与自身的最后日志索引）等核心逻辑，是日志状态的关键标识。
int Raft::getLastLogIndex() {
    int lastLogIndex = -1;  // 用于接收最后一条日志的索引
    int _ = -1;             // 占位变量，忽略最后一条日志的任期（无需使用）
    // 调用核心函数获取最后日志的索引和任期，仅关注索引
    getLastLogIndexAndTerm(&lastLogIndex, &_);
    return lastLogIndex;    // 返回最后一条日志的索引
}

// 获取当前节点最后一条日志的任期（封装了日志与快照的边界处理）
// 作用：任期是 Raft 协议的核心概念，最后一条日志的任期用于选举中判断日志是否“足够新”（UpToDate 函数）、
// 日志同步时的前序日志校验（matchLog 函数）等，确保日志一致性。
int Raft::getLastLogTerm() {
    int _ = -1;             // 占位变量，忽略最后一条日志的索引（无需使用）
    int lastLogTerm = -1;   // 用于接收最后一条日志的任期
    // 调用核心函数获取最后日志的索引和任期，仅关注任期
    getLastLogIndexAndTerm(&_, &lastLogTerm);
    return lastLogTerm;     // 返回最后一条日志的任期
}

// 根据日志索引（logIndex）获取对应的日志任期（term）
// 作用：在 Raft 协议中，日志的任期（term）是判断日志一致性的核心依据（如日志同步时的前序日志匹配、选举中的日志完整性校验等）。
// 该函数封装了“从日志索引查找对应任期”的逻辑，兼顾快照截断后的日志索引处理，是日志状态查询的基础工具函数。
int Raft::getLogTermFromLogIndex(int logIndex) {
    // 断言1：确保请求的日志索引未被快照截断
    // m_lastSnapshotIncludeIndex 是当前节点快照包含的最后一条日志的索引（快照会覆盖该索引及之前的日志，这些日志已从 m_logs 中删除）
    // 若 logIndex < m_lastSnapshotIncludeIndex，说明该日志已被快照覆盖，不存在于当前日志列表中，属于无效请求
    common::Assert(logIndex >= m_lastSnapshotIncludeIndex,
                    common::Format("[func-getSlicesIndexFromLogIndex-rf{%d}]  index{%d} < rf.lastSnapshotIncludeIndex{%d}", 
                    m_me, logIndex, m_lastSnapshotIncludeIndex));
  
    // 获取当前节点最后一条日志的索引（封装了日志与快照的边界处理，确保准确性）
    int lastLogIndex = getLastLogIndex();
  
    // 断言2：确保请求的日志索引不超过当前节点拥有的最后一条日志索引
    // 若 logIndex > lastLogIndex，说明该日志不存在于当前节点（未同步或未生成），属于越界请求
    common::Assert(logIndex <= lastLogIndex, common::Format("[func-getSlicesIndexFromLogIndex-rf{%d}]  logIndex{%d} > lastLogIndex{%d}",
                                              m_me, logIndex, lastLogIndex));
  
    // 核心逻辑：根据日志索引来源（快照或当前日志列表）返回对应任期
    if (logIndex == m_lastSnapshotIncludeIndex) {
        // 情况1：请求的索引是快照包含的最后一条日志索引 → 直接返回快照中记录的任期
        return m_lastSnapshotIncludeTerm;  // m_lastSnapshotIncludeTerm 是快照包含的最后一条日志的任期
    } 
    else {
        // 情况2：请求的索引是快照之后的日志 → 从当前日志列表（m_logs）中查询
        // getSlicesIndexFromLogIndex(logIndex)：将全局日志索引转换为本地日志列表（m_logs）中的索引（因 m_logs 从快照后开始存储）
        // 例如：若快照最后索引为5，m_logs 存储索引6、7、8...的日志，则 logIndex=6 在 m_logs 中的索引为0
        return m_logs[getSlicesIndexFromLogIndex(logIndex)].logterm();  // 返回对应日志的任期
    }
}

int Raft::GetRaftStateSize() { return m_persister->RaftStateSize(); }

// 将全局日志索引（logIndex）转换为本地日志切片（m_logs）的数组索引
// 作用：Raft 中通过快照（Snapshot）压缩旧日志后，本地日志列表（m_logs）仅保留快照之后的日志条目。
// 由于全局日志索引是连续递增的（如 1,2,3,...N），而 m_logs 只从“快照最后索引 + 1”开始存储，两者存在偏移。
// 该函数负责消除这种偏移，将全局索引转换为 m_logs 的数组索引，确保能正确访问本地日志条目，是日志读写的基础工具函数。
int Raft::getSlicesIndexFromLogIndex(int logIndex) {
    // 断言1：确保 logIndex 是快照之后的日志索引（不在快照覆盖范围内）
    // m_lastSnapshotIncludeIndex 是快照包含的最后一条日志索引（快照覆盖该索引及之前的所有日志，这些日志已从 m_logs 中删除）
    // 若 logIndex <= m_lastSnapshotIncludeIndex，说明该日志属于快照范围，不存在于 m_logs 中，访问会越界，故触发断言
    common::Assert(logIndex > m_lastSnapshotIncludeIndex,
                common::Format("[func-getSlicesIndexFromLogIndex-rf{%d}]  index{%d} <= rf.lastSnapshotIncludeIndex{%d}", 
                m_me, logIndex, m_lastSnapshotIncludeIndex));
    
    // 获取当前节点最后一条日志的全局索引（封装了日志与快照的边界处理）
    int lastLogIndex = getLastLogIndex();
    
    // 断言2：确保 logIndex 不超过当前节点拥有的最后一条日志索引
    // 若 logIndex > lastLogIndex，说明该日志不存在于当前节点（未同步或未生成），访问 m_logs 会越界，故触发断言
    common::Assert(logIndex <= lastLogIndex, common::Format("[func-getSlicesIndexFromLogIndex-rf{%d}]  logIndex{%d} > lastLogIndex{%d}",
                                              m_me, logIndex, lastLogIndex));
    
    // 核心转换逻辑：计算 m_logs 中的数组索引
    // 原理：m_logs 中第一条日志的全局索引 = m_lastSnapshotIncludeIndex + 1，对应的数组索引为 0
    // 因此，全局索引 logIndex 与 m_logs 数组索引的偏移量为（m_lastSnapshotIncludeIndex + 1）
    // 即：SliceIndex = logIndex - (m_lastSnapshotIncludeIndex + 1) = logIndex - m_lastSnapshotIncludeIndex - 1
    int SliceIndex = logIndex - m_lastSnapshotIncludeIndex - 1;
    return SliceIndex;
}

// Candidate 向指定节点发送投票请求并处理响应，实现 Raft 选举机制
bool Raft::sendRequestVote(int server, 
                          std::shared_ptr<raftRpcProctoc::RequestVoteArgs> args,
                          std::shared_ptr<raftRpcProctoc::RequestVoteReply> reply, 
                          std::shared_ptr<int> votedNum) {
    // 记录请求发送开始时间（用于计算耗时）
    auto start = common::Now();
    // 调试日志：打印发送投票请求的节点ID、目标节点ID、当前任期及最后日志索引
    common::DPrintf("[func-sendRequestVote rf{%d}] 向server{%d} 发送 RequestVote 开始", 
                    m_me, m_currentTerm, getLastLogIndex());

    // 发送 RPC 请求：调用目标节点的 RequestVote 接口
    // ok 仅表示网络通信是否成功，与是否获得投票无关
    bool ok = m_peers[server]->RequestVote(args.get(), reply.get());

    // 调试日志：打印请求完成时间及耗时
    common::DPrintf("[func-sendRequestVote rf{%d}] 向server{%d} 发送 RequestVote 完毕，耗时:{%d} ms", 
            m_me, m_currentTerm, getLastLogIndex(), common::Now() - start);

    // 若网络通信失败（如目标节点宕机），直接返回失败结果
    if (!ok) {
        return ok;  // 注：此处处理网络异常，避免后续无效逻辑（原注释提到不处理会导致测试失败）
    }

    // 加锁：处理响应时操作共享状态（任期、节点状态等），需保证线程安全
    std::lock_guard<std::mutex> lg(m_mtx);

    // 步骤1：处理任期冲突（Raft 安全性核心）
    // 若目标节点的任期 > 当前 Candidate 的任期 → 发现更新任期，自身转为 Follower
    if (reply->term() > m_currentTerm) {
        m_status = Follower;          // "三变"之一：切换为 Follower
        m_currentTerm = reply->term();// "三变"之二：更新任期为目标节点的任期
        m_votedFor = -1;              // "三变"之三：重置投票记录（新任期未投票）
        persist();                    // 持久化新状态（防止崩溃丢失）
        return true;
    } 
    // 若目标节点的任期 < 当前任期 → 目标节点过时，无需处理
    else if (reply->term() < m_currentTerm) {
        return true;
    }

    // 断言：经过任期检查后，响应的任期必须与当前节点任期一致（否则为逻辑错误）
    common::Assert(reply->term() == m_currentTerm, 
                    common::Format("assert {reply.Term==rf.currentTerm} fail"));

    // 步骤2：处理未获得投票的情况
    if (!reply->votegranted()) {
        return true;  // 未获得该节点投票，无需进一步处理
    }

    // 步骤3：统计同意票数（获得该节点投票）
    *votedNum = *votedNum + 1;

    // 步骤4：检查是否获得多数票（超过集群节点半数）
    if (*votedNum >= m_peers.size() / 2 + 1) {
        // 重置票数计数器（避免重复计数）
        *votedNum = 0;

        // 断言：确保不会在同一任期内重复成为 Leader（逻辑错误检查）
        if (m_status == Leader) {
            common::Assert(false,
                        common::Format("[func-sendRequestVote-rf{%d}]  term:{%d} 同一个term当两次领导，error", 
                        m_me, m_currentTerm));
        }

        // 晋升为 Leader
        m_status = Leader;

        // 调试日志：打印选举成功信息
        common::DPrintf("[func-sendRequestVote rf{%d}] elect success  ,current term:{%d} ,lastLogIndex:{%d}\n", 
                        m_me, m_currentTerm, getLastLogIndex());

        // 初始化 Leader 用于跟踪 Follower 日志同步进度的变量
        int lastLogIndex = getLastLogIndex();  // 获取当前最后一条日志的索引
        for (int i = 0; i < m_nextIndex.size(); i++) {
            m_nextIndex[i] = lastLogIndex + 1;  // nextIndex 初始化为最后日志索引+1（下一条待同步日志）
            m_matchIndex[i] = 0;                // matchIndex 初始化为0（尚未同步任何日志）
        }

        // 立即发送心跳，向集群宣告 Leadership（避免 Follower 超时发起新选举）
        std::thread t(&Raft::doHeartBeat, this);
        t.detach();  // 异步发送，不阻塞当前逻辑

        // 持久化 Leader 状态（任期、日志等）
        persist();
    }

    // 返回通信成功状态
    return true;
}

// Leader 向指定 Follower 发送 AppendEntries RPC 请求，用于日志同步或心跳
bool Raft::sendAppendEntries(int server, std::shared_ptr<raftRpcProctoc::AppendEntriesArgs> args,
                            std::shared_ptr<raftRpcProctoc::AppendEntriesReply> reply,
                            std::shared_ptr<int> appendNums) {
    // 注释说明：此处的 "ok" 仅表示网络通信是否成功，与 Follower 是否接受日志无关
    // 若网络不通，直接返回失败，无需重试
    // todo：需补充重试逻辑，确保日志最终被 Follower 存储

    // 打印调试日志：记录发送开始，包含当前节点 ID、目标节点 ID 及待同步日志数量
    common::DPrintf("[func-Raft::sendAppendEntries-raft{%d}] leader 向节点{%d}发送AE rpc開始 ， args->entries_size():{%d}", 
                    m_me, server, args->entries_size());

    // 调用底层 RPC 接口发送请求，获取网络通信结果（ok 为 true 表示通信成功）
    bool ok = m_peers[server]->AppendEntries(args.get(), reply.get());

    // 若网络通信失败（如节点宕机、网络分区），打印日志并返回失败
    if (!ok) {
        common::DPrintf("[func-Raft::sendAppendEntries-raft{%d}] leader 向节点{%d}发送AE rpc失敗", m_me, server);
        return ok;
    }

    // 网络通信成功，打印日志
    common::DPrintf("[func-Raft::sendAppendEntries-raft{%d}] leader 向节点{%d}发送AE rpc成功", m_me, server);

    // 若 Follower 响应状态为 "断开连接"，直接返回（无需进一步处理）
    if (reply->appstate() == Disconnected) {
        return ok;
    }

    // 加锁保护共享状态（任期、节点状态等），避免多线程冲突
    std::lock_guard<std::mutex> lg1(m_mtx);

    // 处理 Follower 的响应，核心是维护任期一致性（Raft 协议安全性基础）
    // 1. 若 Follower 的任期 > 当前 Leader 的任期：
    //    - 说明 Leader 已过时（可能有新 Leader 当选），需立即转为 Follower
    if (reply->term() > m_currentTerm) {
        m_status = Follower;          // 降级为 Follower
        m_currentTerm = reply->term();// 更新任期为 Follower 的任期（同步到最新）
        m_votedFor = -1;              // 重置投票记录（新任期未投票）
        return ok;
    } 
    // 2. 若 Follower 的任期 < 当前 Leader 的任期：
    //    - 说明 Follower 过时，无需处理（Leader 保持当前状态）
    else if (reply->term() < m_currentTerm) {
        common::DPrintf("[func -sendAppendEntries  rf{%d}]  节点：{%d}的term{%d}<rf{%d}的term{%d}\n", 
                m_me, server, reply->term(), m_me, m_currentTerm);
        return ok;
    }

    // 若当前节点已不是 Leader，则无需处理响应（避免非 Leader 节点修改同步状态）
    if (m_status != Leader) {
        // 非 Leader 节点不参与日志同步决策，直接返回通信结果
        return ok;
    }

    // 断言：确保 Follower 响应的任期与当前 Leader 的任期一致（经过前面的任期检查后必须满足）
    // 若不一致，说明逻辑存在漏洞，触发调试断言失败
    common::Assert(reply->term() == m_currentTerm,
                common::Format("reply.Term{%d} != rf.currentTerm{%d}   ", reply->term(), m_currentTerm));

    // 处理 Follower 响应失败的情况（日志同步未成功）
    if (!reply->success()) {
        // 日志同步失败通常是因为前序日志不匹配（如 Follower 缺失 Leader 发送的前序日志）
        // 若 Follower 返回了建议的 nextIndex（非 -100 表示有效），则更新该 Follower 的 nextIndex
        if (reply->updatenextindex() != -100) {
            // 调试日志：记录 Follower 日志不匹配，需回缩 nextIndex（减少后续重试次数）
            common::DPrintf("[func -sendAppendEntries  rf{%d}]  返回的日志term相等，但是不匹配，回缩nextIndex[%d]：{%d}\n", 
                            m_me, server, reply->updatenextindex());
            // 更新 nextIndex 为 Follower 建议的值（Follower 告知自己能匹配的最大索引）
            m_nextIndex[server] = reply->updatenextindex();
            // 注意：失败时不更新 matchIndex（matchIndex 仅在同步成功后更新）
        }
        // 注：nextIndex 并非冗余，它记录了 Leader 下次向该 Follower 发送日志的起始索引，是 Raft 高效同步的关键
    } 
    // 处理 Follower 响应成功的情况（日志同步成功）
    else {
        // 统计成功同步当前日志的节点数量（appendNums 用于判断是否达到多数节点）
        *appendNums = *appendNums + 1;
        // 调试日志：记录该 Follower 同步成功，及当前成功节点数
        common::DPrintf("---------------------------tmp------------------------- 节点{%d}返回true,当前appendNums{%d}", 
                        server, *appendNums);

        // 更新该 Follower 的 matchIndex（已成功同步的最大日志索引）
        // 取当前 matchIndex 与本次同步的最后日志索引的最大值（避免重复同步导致的索引回退）
        m_matchIndex[server] = std::max(m_matchIndex[server], args->prevlogindex() + args->entries_size());
        // 下次同步从当前已同步索引的下一个开始（matchIndex + 1）
        m_nextIndex[server] = m_matchIndex[server] + 1;

        // 获取当前 Leader 最后一条日志的索引（用于边界检查）
        int lastLogIndex = getLastLogIndex();

        // 断言：确保 nextIndex 不超过 Leader 最后一条日志索引 + 1（避免越界）
        common::Assert(m_nextIndex[server] <= lastLogIndex + 1,
                        common::Format("error msg:rf.nextIndex[%d] > lastLogIndex+1, len(rf.logs) = %d   lastLogIndex{%d} = %d", 
                        server, m_logs.size(), server, lastLogIndex));

        // 若成功同步当前日志的节点数已超过集群半数（满足分布式一致性）
        if (*appendNums >= 1 + m_peers.size() / 2) {
            // 重置计数器（避免重复提交，保证幂等性）
            *appendNums = 0;

            // 仅当本次同步的日志包含当前任期的条目时，才更新提交索引（Raft 安全性要求）
            // 原因：Raft 仅允许提交当前任期的日志，旧任期日志需依赖当前任期日志的提交而间接提交
            if (args->entries_size() > 0) {
                // 调试日志：打印本次同步的最后一条日志的任期，验证是否为当前任期
                common::DPrintf("args->entries(args->entries_size()-1).logterm(){%d}   m_currentTerm{%d}",
                                args->entries(args->entries_size() - 1).logterm(), m_currentTerm);
            }

            // 若本次同步的最后一条日志是当前任期的，则更新提交索引
            if (args->entries_size() > 0 && args->entries(args->entries_size() - 1).logterm() == m_currentTerm) {
                // 调试日志：记录提交索引更新（从旧值到新值）
                common::DPrintf(
                    "---------------------------tmp------------------------- 当前term有log成功提交，更新leader的m_commitIndex "
                    "from{%d} to{%d}", m_commitIndex, args->prevlogindex() + args->entries_size());

                // 提交索引取当前值与本次同步的最后日志索引的最大值（确保提交最新的可提交日志）
                m_commitIndex = std::max(m_commitIndex, args->prevlogindex() + args->entries_size());
            }

            // 断言：提交索引不能超过 Leader 最后一条日志的索引（避免提交不存在的日志）
            common::Assert(m_commitIndex <= lastLogIndex,
                            common::Format("[func-sendAppendEntries,rf{%d}] lastLogIndex:%d  rf.commitIndex:%d\n", 
                            m_me, lastLogIndex, m_commitIndex));
        }
    }

    // 返回 RPC 通信结果（true 表示通信成功，false 表示失败）
    return ok;
}

void Raft::pushMsgToKvServer(ApplyMsg msg) { applyChan->Push(msg); }

// 从序列化数据中恢复 Raft 节点的核心状态（反序列化）
void Raft::readPersist(std::string data) {
    // 步骤1：检查数据是否为空（若为空，无需恢复，直接返回）
    if (data.empty()) {
        return;
    }

    // 步骤2：创建字符串流，用于读取序列化数据
    std::stringstream iss(data);  // 将输入的序列化字符串转换为流，便于 Boost 库读取

    // 步骤3：创建文本输入归档器（反序列化核心工具）
    // text_iarchive 是 Boost 序列化库的文本输入归档器，用于将流中的数据反序列化为对象
    boost::archive::text_iarchive ia(iss);

    // 步骤4：定义临时对象，用于存储反序列化后的状态
    // BoostPersistRaftNode 是与 persistData() 中对应的结构体，封装了所有需要持久化的状态
    BoostPersistRaftNode boostPersistRaftNode;

    // 步骤5：执行反序列化（从流中读取数据并填充到临时对象）
    // >> 操作符已通过 Boost 库重载，实现将流中的序列化数据转换为对象
    ia >> boostPersistRaftNode;

    // 步骤6：用反序列化得到的状态更新节点的内存状态（核心恢复逻辑）
    m_currentTerm = boostPersistRaftNode.m_currentTerm;  // 恢复当前任期
    m_votedFor = boostPersistRaftNode.m_votedFor;        // 恢复当前任期的投票记录
    // 恢复快照相关信息（快照包含的最后日志索引和任期）
    m_lastSnapshotIncludeIndex = boostPersistRaftNode.m_lastSnapshotIncludeIndex;
    m_lastSnapshotIncludeTerm = boostPersistRaftNode.m_lastSnapshotIncludeTerm;

    // 步骤7：恢复日志条目（日志是状态机恢复的核心数据）
    m_logs.clear();  // 先清空当前日志列表（避免与恢复的日志冲突）
    // 遍历反序列化得到的日志字符串列表，逐个解析为 LogEntry 对象并加入本地日志
    for (auto& item : boostPersistRaftNode.m_logs) {
        raftRpcProctoc::LogEntry logEntry;  // 日志条目对象（通常基于 Protobuf 定义）
        logEntry.ParseFromString(item);     // 将字符串反序列化为 LogEntry（Protobuf 提供的解析方法）
        m_logs.emplace_back(logEntry);      // 将解析后的日志条目加入本地日志列表
    }
}


// 将 Raft 节点的核心状态数据序列化，为持久化做准备
std::string Raft::persistData() {
    // 步骤1：创建一个用于持久化的临时对象，存储需要序列化的状态
    // BoostPersistRaftNode 是一个自定义结构体，用于封装待序列化的 Raft 状态
    BoostPersistRaftNode boostPersistRaftNode;

    // 步骤2：复制 Raft 节点的核心状态到临时对象中
    // 这些状态是节点恢复时必须的关键信息，缺一不可
    boostPersistRaftNode.m_currentTerm = m_currentTerm;  // 当前任期（Raft 协议的核心时序标识）
    boostPersistRaftNode.m_votedFor = m_votedFor;        // 当前任期内已投票的节点 ID（-1 表示未投票）
    // 快照相关信息（快照是压缩旧日志的机制，记录快照包含的最后一条日志的索引和任期）
    boostPersistRaftNode.m_lastSnapshotIncludeIndex = m_lastSnapshotIncludeIndex;
    boostPersistRaftNode.m_lastSnapshotIncludeTerm = m_lastSnapshotIncludeTerm;

    // 步骤3：序列化日志条目
    // 遍历本地日志列表 m_logs，将每条日志序列化为字符串后存入临时对象
    // 日志条目包含命令、索引、任期等，是状态机恢复的核心数据
    for (auto& item : m_logs) {
        // 调用日志条目的 SerializeAsString() 方法（通常基于 Protobuf 实现）
        boostPersistRaftNode.m_logs.push_back(item.SerializeAsString());
    }
  
    // 步骤4：使用 Boost 序列化库将临时对象转换为字符串
    std::stringstream ss;  // 字符串流，用于存储序列化后的二进制数据
    // 创建文本输出归档器（text_oarchive），用于将对象序列化到字符串流
    boost::archive::text_oarchive oa(ss);
    // 将临时对象序列化到流中（<< 操作符已通过 Boost 库重载，实现对象序列化）
    oa << boostPersistRaftNode;

    // 步骤5：返回序列化后的字符串（后续会被写入磁盘）
    return ss.str();
}

// 获取当前 Raft 节点的核心状态（任期和是否为 Leader）
void Raft::GetState(int* term, bool* isLeader) {
    // 加锁：获取共享资源（任期和状态）前加互斥锁，保证线程安全
    m_mtx.lock();
    
    // 延迟解锁：使用 common::DEFER 注册解锁操作，确保函数退出时无论是否发生异常都能释放锁
    // 注：原注释提到“暂时不清楚会不会导致死锁”，实际 DEFER 机制会在当前作用域结束时执行解锁，
    // 只要锁的粒度合理（不嵌套其他锁），通常不会死锁
    common::DEFER [&]() {
        m_mtx.unlock();
    };
  
    // 读取当前节点的任期，通过输出参数返回
    *term = m_currentTerm;
    // 判断当前节点状态是否为 Leader，通过输出参数返回
    *isLeader = (m_status == Leader);
}

// 处理 Leader 发送的快照安装请求，更新本地状态并通知应用层加载快照
void Raft::InstallSnapshot(const raftRpcProctoc::InstallSnapshotRequest* args,
                            raftRpcProctoc::InstallSnapshotResponse* reply) {
    // 加锁：确保处理快照期间节点状态（日志、任期等）不被其他线程修改
    m_mtx.lock();
    // 延迟解锁：函数退出时自动释放锁（无论 return 位置，避免死锁）
    common::DEFER [&]() { m_mtx.unlock(); };

    // 步骤1：验证 Leader 任期合法性（Raft 安全性核心）
    // 若 Leader 任期 < 当前节点任期 → Leader 已过时，拒绝处理并返回自身任期
    if (args->term() < m_currentTerm) {
        reply->set_term(m_currentTerm);  // 告知 Leader 最新任期，使其更新自身状态
        return;
    }

    // 步骤2：若 Leader 任期 > 当前节点任期 → 发现更新任期，自身转为 Follower 并同步任期
    if (args->term() > m_currentTerm) {
        m_currentTerm = args->term();    // 同步到最新任期
        m_votedFor = -1;                 // 重置投票记录（新任期未投票）
        m_status = Follower;             // 切换为 Follower
        persist();                       // 持久化新状态（防止崩溃丢失）
    }

    // 步骤3：确认自身状态为 Follower（即使任期相同，Candidate 也需转为 Follower）
    m_status = Follower;
    // 重置选举定时器（收到 Leader 消息，避免触发新选举）
    m_lastResetElectionTime = common::Now();

    // 步骤4：检查快照是否过时（避免覆盖更新的本地快照）
    // 若请求的快照索引 ≤ 本地已有快照索引 → 快照过时，无需处理
    if (args->lastsnapshotincludeindex() <= m_lastSnapshotIncludeIndex) {
        return;
    }

    // 步骤5：截断本地日志（保留快照之后的日志，丢弃被快照覆盖的旧日志）
    auto lastLogIndex = getLastLogIndex();  // 获取本地最后一条日志的索引

    if (lastLogIndex > args->lastsnapshotincludeindex()) {
        // 情况1：本地日志索引超过快照索引 → 截断快照索引之前的日志
        // getSlicesIndexFromLogIndex(...)：将快照索引转换为本地日志列表的数组索引
        // +1 表示包含快照索引对应的日志（该日志已被快照覆盖，需删除）
        m_logs.erase(m_logs.begin(), 
                    m_logs.begin() + getSlicesIndexFromLogIndex(args->lastsnapshotincludeindex()) + 1);
    } 
    else {
        // 情况2：本地日志索引 ≤ 快照索引 → 所有本地日志均被快照覆盖，清空日志列表
        m_logs.clear();
    }

    // 步骤6：更新节点状态（快照元数据、提交索引、应用索引）
    // 提交索引和应用索引取最大值（确保不小于快照索引，快照内日志已默认提交和应用）
    m_commitIndex = std::max(m_commitIndex, args->lastsnapshotincludeindex());
    m_lastApplied = std::max(m_lastApplied, args->lastsnapshotincludeindex());
    // 更新快照元数据（记录当前快照包含的最后日志索引和任期）
    m_lastSnapshotIncludeIndex = args->lastsnapshotincludeindex();
    m_lastSnapshotIncludeTerm = args->lastsnapshotincludeterm();

    // 步骤7：构造响应（返回当前节点任期，供 Leader 验证）
    reply->set_term(m_currentTerm);

    // 步骤8：通知应用层加载快照（如 KV 存储需从快照恢复状态）
    ApplyMsg msg;
    msg.SnapshotValid = true;               // 标记为快照消息
    msg.Snapshot = args->data();            // 快照数据（序列化的应用层状态）
    msg.SnapshotTerm = args->lastsnapshotincludeterm();  // 快照对应的任期
    msg.SnapshotIndex = args->lastsnapshotincludeindex();// 快照对应的日志索引

    // 启动新线程发送快照消息（避免阻塞 Raft 核心逻辑）
    std::thread t(&Raft::pushMsgToKvServer, this, msg);
    t.detach();  // 分离线程，后台执行

    // 步骤9：持久化新快照和节点状态（确保崩溃后可恢复）
    // persistData()：序列化当前节点状态（任期、日志等）
    // Save()：将状态和快照数据写入稳定存储（如磁盘）
    m_persister->Save(persistData(), args->data());
}

// 处理其他节点（Candidate）发送的投票请求（RequestVote RPC）
// 作用：根据 Raft 协议的选举规则，决定是否给请求投票的 Candidate 授予选票，
// 是 Raft 选举机制的核心逻辑（确保只有日志完整的节点能当选 Leader）。
void Raft::RequestVote(const raftRpcProctoc::RequestVoteArgs* args, raftRpcProctoc::RequestVoteReply* reply) {
    // 加锁保证线程安全：多线程环境下，状态（任期、投票记录等）的读写需互斥
    std::lock_guard<std::mutex> lg(m_mtx);
  
    // 延迟执行持久化：函数退出前自动调用 persist()，确保投票状态、任期等关键信息写入稳定存储
    // （崩溃重启后可恢复，是 Raft 容错性的核心保障）
    common::DEFER [&]() {
        persist();  // 先持久化再释放锁，避免状态丢失
    };
  
    // 情况1：请求的任期（Candidate 的任期）小于当前节点的任期 → Candidate 已过时，拒绝投票
    // Raft 规则：节点不会给任期小于自己的 Candidate 投票（确保旧任期的节点无法当选）
    if (args->term() < m_currentTerm) {
        reply->set_term(m_currentTerm);  // 回复自己的当前任期（让 Candidate 更新任期）
        reply->set_votestate(Expire);    // 标记投票状态为"过时"（Candidate 任期无效）
        reply->set_votegranted(false);   // 拒绝授予选票
        return;
    }
  
    // 情况2：请求的任期大于当前节点的任期 → 发现更新的任期，自身转为 Follower 并同步任期
    // Raft 规则：任何节点收到比自己大的任期时，必须更新自身任期并转为 Follower
    if (args->term() > m_currentTerm) {
        m_status = Follower;             // 切换为 Follower（新任期下只能先作为追随者）
        m_currentTerm = args->term();    // 更新自身任期为请求的任期（同步到最新任期）
        m_votedFor = -1;                 // 重置投票记录（新任期内尚未投票给任何节点）
    }
  
    // 断言：经过上述处理后，请求的任期必须与当前节点的任期一致（否则为逻辑错误）
    common::Assert(args->term() == m_currentTerm,
                    common::Format("[func--rf{%d}] 前面校验过args.Term==rf.currentTerm，这里却不等", m_me));
  
    // 步骤3：检查 Candidate 的日志是否"足够新"（Raft 核心安全性：只有日志至少与自己一样新的节点才能当选 Leader）
    int lastLogTerm = getLastLogTerm();  // 获取当前节点最后一条日志的任期
    // UpToDate() 函数判断：Candidate 的最后一条日志的任期和索引是否 ≥ 当前节点的（即日志不旧于自己）
    if (!UpToDate(args->lastlogindex(), args->lastlogterm())) {
        // 若 Candidate 日志更旧（任期更小，或任期相同但索引更小），拒绝投票
        if (args->lastlogterm() < lastLogTerm) {
            // 调试日志（注释）：Candidate 日志任期更小，拒绝投票
        } 
        else {
            // 调试日志（注释）：Candidate 日志任期相同但索引更小，拒绝投票
        }
        reply->set_term(m_currentTerm);    // 回复当前任期
        reply->set_votestate(Voted);       // 标记投票状态为"已投票"（实际是拒绝给该 Candidate 投票）
        reply->set_votegranted(false);     // 拒绝授予选票
        return;
    }
  
    // 步骤4：检查当前节点是否已在本任期内投票给其他节点
    // Raft 规则：一个任期内，节点最多给一个 Candidate 投票（"一票一投"原则）
    if (m_votedFor != -1 && m_votedFor != args->candidateid()) {
        // 已投票给其他节点，拒绝给当前 Candidate 投票
        reply->set_term(m_currentTerm);    // 回复当前任期
        reply->set_votestate(Voted);       // 标记已投票给其他节点
        reply->set_votegranted(false);     // 拒绝授予选票
        return;
    } 
    else {
        // 未投票或已投票给当前 Candidate → 授予选票
        m_votedFor = args->candidateid();  // 记录投票给该 Candidate
        m_lastResetElectionTime = common::Now();   // 重置选举定时器（避免刚投票就因超时发起新选举）
        reply->set_term(m_currentTerm);    // 回复当前任期
        reply->set_votestate(Normal);      // 标记投票状态为"正常"（成功授予选票）
        reply->set_votegranted(true);      // 同意授予选票
        return;
    }
}

void Raft::Start(common::Op command, int* newLogIndex, int* newLogTerm, bool* isLeader) {
    // 加锁保证线程安全：防止多线程同时修改日志或节点状态（如任期、角色）
    std::lock_guard<std::mutex> lg1(m_mtx);  // 离开作用域时自动解锁，避免死锁

    // 步骤1：检查当前节点是否为 Leader
    if (m_status != Leader) {
        // 非 Leader 节点无法处理客户端命令，返回错误信息
        common::DPrintf("[func-Start-rf{%d}]  is not leader", m_me);  // 日志打印当前节点ID和非Leader状态
        *newLogIndex = -1;    // 无效索引（标记命令未处理）
        *newLogTerm = -1;     // 无效任期
        *isLeader = false;    // 明确告知调用方当前不是Leader
        return;
    }

    // 步骤2：构造新日志条目（仅Leader可执行）
    raftRpcProctoc::LogEntry newLogEntry;  // 日志条目对象
    newLogEntry.set_command(command.AsString());  // 存储客户端命令（序列化后的字符串）
    newLogEntry.set_logterm(m_currentTerm);       // 日志条目所属任期（当前Leader的任期）
    newLogEntry.set_logindex(getNewCommandIndex());// 日志索引（最后一条日志索引+1，确保唯一性）
    m_logs.emplace_back(newLogEntry);  // 将新日志加入本地日志列表（emplace_back比push_back更高效）

    // 步骤3：记录当前最后一条日志的索引（用于调试）
    int lastLogIndex = getLastLogIndex();  // 获取最新日志索引（封装了快照与日志的边界处理）

    // 调试日志：打印当前节点ID、最后日志索引和客户端命令
    common::DPrintf("[func-Start-rf{%d}]  lastLogIndex:%d,command:%s\n", m_me, lastLogIndex, &command);

    // 注释说明：
    // Leader需要持续向Follower发送AppendEntries（AE）以同步日志和维持心跳
    // 此处设计为：新命令加入日志后不立即触发同步，而是等待Leader的心跳定时器自然触发
    // （原计划修改为"收到命令后立即同步"，但存在未解决的问题，标记为TODO）
    // rf.timer.Reset(10) // 临时注释：尝试立即同步的方案，待修复

    // 步骤4：持久化新日志（确保崩溃后可恢复）
    persist();  // 调用持久化函数，将新日志和当前状态写入稳定存储（如磁盘）

    // 步骤5：返回处理结果（仅Leader执行）
    *newLogIndex = newLogEntry.logindex();  // 新日志的索引（供调用方跟踪命令状态）
    *newLogTerm = newLogEntry.logterm();    // 新日志的任期
    *isLeader = true;                       // 明确告知调用方当前是Leader
}

// 生成并存储快照，压缩已提交的旧日志以减少存储开销
void Raft::Snapshot(int index, std::string snapshot) {
    // 加锁：确保快照生成过程中状态（日志、快照元数据等）不被其他线程修改
    std::lock_guard<std::mutex> lg(m_mtx);
  
    // 步骤1：校验快照索引的有效性（拒绝无效快照请求）
    // 情况1：请求的快照索引 <= 当前已有的快照索引 → 快照过时（无需重复生成）
    // 情况2：请求的快照索引 > 已提交日志的最大索引 → 快照包含未提交的日志（不安全，可能被回滚）
    if (m_lastSnapshotIncludeIndex >= index || index > m_commitIndex) {
        // 打印拒绝原因日志
        common::DPrintf("[func-Snapshot-rf{%d}] 拒绝生成快照：请求索引%d 无效（当前快照索引%d 更大，或索引超过已提交日志）",
                        m_me, index, m_lastSnapshotIncludeIndex);
        return;
    }

    // 步骤2：记录当前最后一条日志的索引（用于后续校验快照前后的日志完整性）
    auto lastLogIndex = getLastLogIndex();
  
    // 步骤3：计算新快照的元数据（快照包含的最后日志索引和任期）
    int newLastSnapshotIncludeIndex = index;  // 新快照覆盖到的日志索引
    // 获取该索引对应的日志任期（用于日志同步时的前序校验）
    int newLastSnapshotIncludeTerm = m_logs[getSlicesIndexFromLogIndex(index)].logterm();

    // 步骤4：截取快照索引之后的日志（保留未被快照覆盖的日志）
    std::vector<raftRpcProctoc::LogEntry> trunckedLogs;  // 存储截取后的日志
    // 遍历从 index+1 到最后一条日志的所有条目，加入截取后的日志列表
    for (int i = index + 1; i <= getLastLogIndex(); i++) {
        // getSlicesIndexFromLogIndex(i)：将全局日志索引转换为本地日志列表的数组索引
        trunckedLogs.push_back(m_logs[getSlicesIndexFromLogIndex(i)]);
    }

    // 步骤5：更新节点状态（快照元数据和日志列表）
    m_lastSnapshotIncludeIndex = newLastSnapshotIncludeIndex;  // 更新快照索引
    m_lastSnapshotIncludeTerm = newLastSnapshotIncludeTerm;    // 更新快照任期
    m_logs = trunckedLogs;  // 替换日志列表为截取后的新日志（旧日志被快照替代）
    // 更新已提交索引和已应用索引（确保不小于快照索引，快照内的日志已默认提交和应用）
    m_commitIndex = std::max(m_commitIndex, index);
    m_lastApplied = std::max(m_lastApplied, index);
  
    // 步骤6：持久化快照数据和当前节点状态
    // persistData()：序列化当前状态（任期、投票记录、新日志等）
    // Save()：将序列化状态和快照数据写入稳定存储（如磁盘）
    m_persister->Save(persistData(), snapshot);
  
    // 步骤7：打印快照生成结果日志（调试用）
    common::DPrintf("[SnapShot]节点 %d 生成快照：索引{%d}，任期{%d}，剩余日志条数{%d}", 
                    m_me, index, m_lastSnapshotIncludeTerm, m_logs.size());

    // 步骤8：校验快照前后的日志完整性（断言确保无日志丢失或重复）
    // 校验逻辑：剩余日志条数 + 新快照索引 = 快照前的最后日志索引
    common::Assert(m_logs.size() + m_lastSnapshotIncludeIndex == lastLogIndex,
                common::Format("快照后日志不完整：剩余日志数{%d} + 快照索引{%d} != 原最后日志索引{%d}", 
                m_logs.size(), m_lastSnapshotIncludeIndex, lastLogIndex));
}

void Raft::init(std::vector<std::shared_ptr<RaftRpcUtil>> peers,    // 集群中其他节点的 RPC 通信接口列表
                int me,                                             // 当前节点的 ID
                std::shared_ptr<Persister> persister,               // 持久化工具（用于读写磁盘数据）
                std::shared_ptr<common::LockQueue<ApplyMsg>> applyCh) {     // 用于向应用层（如 KV 服务器）发送已提交日志的消息队列
    // 步骤1：保存外部传入的核心依赖
    m_peers = peers;          // 存储集群节点通信接口，用于后续发送 RPC（如投票、日志同步）
    m_persister = persister;  // 保存持久化工具，用于读写节点状态（崩溃恢复的关键）
    m_me = me;                // 记录当前节点 ID，用于标识自身在集群中的身份

    // 加锁：初始化过程中修改共享状态，需保证线程安全
    m_mtx.lock();

    // 步骤2：初始化应用层通信通道
    this->applyChan = applyCh;  // 保存消息队列，后续将已提交的日志通过此队列发送给应用层

    // 步骤3：初始化 Raft 核心状态变量（默认值）
    m_currentTerm = 0;                  // 当前任期，初始为 0（集群启动时所有节点从任期 0 开始）
    m_status = Follower;                // 初始状态为 Follower（新节点加入集群时先作为追随者）
    m_commitIndex = 0;                  // 已提交日志的最大索引（初始为 0，无已提交日志）
    m_lastApplied = 0;                  // 已应用到状态机的最大日志索引（初始为 0）
    m_logs.clear();                     // 清空日志列表（后续可能从持久化数据恢复）
    
    // 初始化 Leader 用于跟踪 Follower 日志同步进度的数组
    for (int i = 0; i < m_peers.size(); i++) {
        m_matchIndex.push_back(0);  // 记录每个 Follower 已同步的最大日志索引（初始为 0）
        m_nextIndex.push_back(0);   // 记录下一次向 Follower 发送日志的起始索引（初始为 0）
    }
    m_votedFor = -1;  // 记录当前任期内已投票的节点 ID（-1 表示未投票）

    // 步骤4：初始化快照相关状态（快照用于压缩旧日志，减少存储和传输开销）
    m_lastSnapshotIncludeIndex = 0;  // 快照包含的最后一条日志的索引（初始无快照，为 0）
    m_lastSnapshotIncludeTerm = 0;   // 快照包含的最后一条日志的任期（初始为 0）
    m_lastResetElectionTime = common::Now(); // 重置选举定时器时间（避免节点刚启动就立即发起选举）
    m_lastResetHearBeatTime = common::Now(); // 重置心跳定时器时间（Leader 相关，初始值无实际意义）

    // 步骤5：从持久化数据恢复状态（崩溃重启时关键操作）
    // 读取之前持久化的节点状态（如任期、投票记录、日志等），覆盖默认值
    readPersist(m_persister->ReadRaftState());
    
    // 若存在快照（快照索引 > 0），更新已应用索引（快照内的日志已默认应用到状态机）
    if (m_lastSnapshotIncludeIndex > 0) {
        m_lastApplied = m_lastSnapshotIncludeIndex;
        // TODO：注释疑问：崩溃恢复时为何不直接读取 commitIndex？
        // 可能原因：commitIndex 是动态变化的，快照生成时已确保其包含的日志均已提交，故无需单独恢复
        // rf.commitIndex = rf.lastSnapshotIncludeIndex   
    }

    // 调试日志：打印初始化完成的节点信息（ID、任期、快照状态）
    common::DPrintf("[Init&ReInit] Sever %d, term %d, lastSnapshotIncludeIndex {%d} , lastSnapshotIncludeTerm {%d}", 
            m_me, m_currentTerm, m_lastSnapshotIncludeIndex, m_lastSnapshotIncludeTerm);

    // 解锁：初始化状态设置完成，释放锁
    m_mtx.unlock();

    // 步骤6：初始化协程管理器（用于高效处理定时器任务）
    // 创建 IO 管理器，管理协程调度（替代传统线程，减少上下文切换开销）
    m_ioManager = std::make_unique<fiber::IOManager>(common::FIBER_THREAD_NUM, common::FIBER_USE_CALLER_THREAD);

    // 步骤7：启动核心定时器协程/线程（驱动 Raft 协议运行的"引擎"）
    // 注释说明：
    // 原设计使用三个线程，现改为协程+线程混合模式：
    // - leaderHearBeatTicker 和 electionTimeOutTicker 执行时间稳定，适合用协程
    // - applierTicker 可能受应用层响应影响，仍用线程避免阻塞协程调度

    // 启动 Leader 心跳定时器协程：定期发送心跳/日志同步请求（维持 Leader 地位）
    // 这个时候还是follower，预启动设计，等到成为leader就开始工作，不是就睡眠
    m_ioManager->scheduler([this]() -> void { this->leaderHearBeatTicker(); });
    // 启动选举超时定时器协程：超时未收到心跳则发起选举（Follower/Candidate 行为）
    m_ioManager->scheduler([this]() -> void { this->electionTimeOutTicker(); });

    // 启动日志应用线程：定期将已提交日志应用到状态机并通知应用层
    std::thread t3(&Raft::applierTicker, this);
    t3.detach();  // 分离线程，使其在后台运行
}

// 处理来自 Leader 的日志同步（或心跳）RPC 请求的接口适配函数
// 作用：作为 RPC 框架的入口，将请求转发给核心处理逻辑 AppendEntries1，并触发 RPC 回调
void Raft::AppendEntries( google::protobuf::RpcController* controller,       // RPC 控制器（用于控制 RPC 调用过程，如取消请求）
                        const ::raftRpcProctoc::AppendEntriesArgs* request,  // 日志同步请求参数（包含任期、前序日志、待同步日志等）
                        ::raftRpcProctoc::AppendEntriesReply* response,      // 日志同步响应结果（包含是否成功、任期等）
                        ::google::protobuf::Closure* done) {                 // RPC 完成回调（用于通知框架处理结果）

    // 调用核心逻辑函数 AppendEntries1 处理日志同步请求
    // AppendEntries1 实现了 Raft 协议中 Follower 接收 Leader 日志的完整逻辑（任期检查、日志匹配、同步等）
    AppendEntries1(request, response);
    
    // 触发 RPC 完成回调，通知 RPC 框架请求已处理完毕
    // 框架会根据 response 向调用方（Leader）返回结果
    done->Run();
}

// 处理来自 Leader 的快照安装 RPC 请求的接口适配函数
// 作用：作为 RPC 框架的入口，将快照请求转发给核心处理逻辑，并触发 RPC 回调
void Raft::InstallSnapshot(google::protobuf::RpcController* controller,             // RPC 控制器
                        const ::raftRpcProctoc::InstallSnapshotRequest* request,    // 快照安装请求参数（包含快照数据、快照索引等）
                        ::raftRpcProctoc::InstallSnapshotResponse* response,        // 快照安装响应结果（包含处理状态、任期等）
                        ::google::protobuf::Closure* done) {                        // RPC 完成回调

    // 调用核心逻辑函数 InstallSnapshot 处理快照安装请求
    // 核心逻辑需验证快照有效性、更新本地快照信息、截断旧日志等
    InstallSnapshot(request, response);
    
    // 触发 RPC 完成回调，通知框架请求处理完毕
    done->Run();
}

// 处理来自 Candidate 的投票请求 RPC 的接口适配函数
// 作用：作为 RPC 框架的入口，将投票请求转发给核心处理逻辑，并触发 RPC 回调
void Raft::RequestVote(google::protobuf::RpcController* controller,     // RPC 控制器
                    const ::raftRpcProctoc::RequestVoteArgs* request,   // 投票请求参数（包含 Candidate 任期、日志信息等）
                    ::raftRpcProctoc::RequestVoteReply* response,       // 投票响应结果（包含是否同意、任期等）
                    ::google::protobuf::Closure* done) {                // RPC 完成回调

    // 调用核心逻辑函数 RequestVote 处理投票请求
    // 核心逻辑实现了 Raft 协议中节点投票的规则（任期检查、日志完整性校验、一票一投等）
    RequestVote(request, response);
    
    // 触发 RPC 完成回调，通知框架请求处理完毕
    done->Run();
}

}   // namespace rafrCore